package manager

import (
	"bufio"
	"fmt"
	"github.com/tianjigames/fairy/model"
	"github.com/tianjigames/fairy/template"
	"github.com/tianjigames/fairy/util"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/logger"
	"io"
	"math"
	"os"
	"strconv"
	"strings"
	"sync"
)

var (
	MapDataManager *mapDataManager
	mapDataManagerOnce sync.Once
)

type mapDataManager struct {
	BaseManager
	m_MapData map[int]*model.MapData
	m_MapNavmesh map[int]map[int]*model.Triangle
}

func NewMapDataManager() *mapDataManager {
	mapDataManagerOnce.Do(func() {
		MapDataManager = &mapDataManager{
			m_MapData: map[int]*model.MapData{},
			m_MapNavmesh: map[int]map[int]*model.Triangle{},
		}
	})
	return MapDataManager
}

func (p *mapDataManager) Init()  {
	p.BaseManager.Init()
	begin := util.Now()

	//家在地图数据
	for _,v := range pitaya.GetTemplates(template.SceneBaseKey) {
		cfg := v.(*template.SceneBase)
		data := model.NewMapData()
		fileName := fmt.Sprintf("./resource/mapdata/%s",cfg.SceneMapData)
		b,err := data.LoadMap(fileName)
		if err != nil {
			logger.Log.Errorf("[MapDataManager] Init failed,error:%s",err.Error())
			return
		}

		if !b {
			continue
		}

		id,err := strconv.ParseInt(cfg.Id,10,32)
		if err != nil {
			logger.Log.Errorf("[MapDataManager] Init failed,error:%s",err.Error())
			return
		}
		p.m_MapData[int(id)] = data

		err = p.loadNavmesh(cfg)
		if err != nil {
			logger.Log.Errorf("[MapDataManager] Init failed,error:%s",err.Error())
			return
		}
	}
	logger.Log.Debugf("加载所有场景地图的三角形网格模型完成,共加载%d个场景,总耗时:%d",len(p.m_MapNavmesh), util.Now() -begin)
}

/**
加载三角形网格模型
 */
func (p *mapDataManager) loadNavmesh(sceneBase *template.SceneBase) error {

	fileName := fmt.Sprintf("./resource/mapdata/%s",strings.Replace(sceneBase.SceneMapData,".path",".obj",1))
	if len(fileName) == 0  {
		return nil
	}

	//begin := util.Now()
	b,err := util.FileUtil.Exist(fileName)
	if err != nil {
		logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
		return err
	}

	if !b {
		return nil
	}

	var f *os.File
	f,err = os.Open(fileName)
	if err != nil {
		logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
		return err
	}
	defer f.Close()

	rd := bufio.NewReader(f)
	var line string
	var data []byte

	i := 0
	j := 0

	var x,y,z float64
	var aIndex,bIndex,cIndex int64
	mapPoint := map[int]*model.Pos{}
	mapTriangle := map[int]*model.Triangle{}

	for {
		data,_,err = rd.ReadLine()
		if err != nil {
			if err != io.EOF {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}
			break
		}


		//line = strings.TrimSpace(string(data))
		line = string(data)
		strs := strings.Split(line," ")
		if len(strs) != 4 {
			continue
		}

		if strs[0] == "v" {
			x,err = strconv.ParseFloat(strs[1],64)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			y,err = strconv.ParseFloat(strs[2],64)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			z,err = strconv.ParseFloat(strs[3],64)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			i ++
			mapPoint[i] = model.NewPos(int(x*(-100)),int(y*100),int(z*100))
		}else if strs[0] == "f" {
			aIndex,err = strconv.ParseInt(strings.Split(strs[1],"/")[0],10,32)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			bIndex,err = strconv.ParseInt(strings.Split(strs[2],"/")[0],10,32)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			cIndex,err = strconv.ParseInt(strings.Split(strs[3],"/")[0],10,32)
			if err != nil {
				logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
				return err
			}

			j ++
			mapTriangle[j] = model.NewTriangle(j,mapPoint[int(aIndex)],mapPoint[int(bIndex)],mapPoint[int(cIndex)])
		}
	}

	countMap := map[int]int{}
	for outerKey,outerValue := range mapTriangle {
		if countMap[outerKey] >= 3 {
			continue
		}

		for innerKey,innerValue := range mapTriangle {
			if outerKey == innerKey || countMap[innerKey] >= 3 {
				continue
			}


			index := p.checkAdjacentTriangle(outerValue,innerValue)
			if index < 0 {//两个三角形没有相邻边
				continue
			}

			if index == 0 {
				outerValue.Link[0] = innerKey
				outerValue.Dist[0] = p.Distance(outerValue.Midpts[0],innerValue.Midpts[1])
				countMap[outerKey] ++

				outerValue.Link[0] = innerKey
				outerValue.Dist[0] = p.Distance(innerValue.Midpts[0],outerValue.Midpts[1])
				countMap[innerKey] ++
			}else if index == 1 {
				outerValue.Link[1] = innerKey
				outerValue.Dist[1] = p.Distance(outerValue.Midpts[1],innerValue.Midpts[2])
				countMap[outerKey] ++

				outerValue.Link[1] = innerKey
				outerValue.Dist[1] = p.Distance(innerValue.Midpts[1],outerValue.Midpts[2])
				countMap[innerKey] ++
			}else if index == 2 {
				outerValue.Link[2] = innerKey
				outerValue.Dist[2] = p.Distance(outerValue.Midpts[2],innerValue.Midpts[0])
				countMap[outerKey] ++

				outerValue.Link[2] = innerKey
				outerValue.Dist[2] = p.Distance(innerValue.Midpts[2],outerValue.Midpts[0])
				countMap[innerKey] ++
			}

			if countMap[outerKey] >= 3 {
				break
			}
		}
	}

	id,err := strconv.ParseInt(sceneBase.Id,10,32)
	if err != nil {
		logger.Log.Errorf("[MapDataManager] loadNavmesh failed,error:%s",err.Error())
		return err
	}
	p.m_MapNavmesh[int(id)] = mapTriangle
	//logger.Log.Debugf("文件：%s,用时:%d",fileName,util.Now() - begin)
	return nil
}

/**
判断两个三角形是否有相邻边
 */
func (p *mapDataManager) checkAdjacentTriangle(t1 *model.Triangle,t2 *model.Triangle) int {
	var num,index1,index2 int
	for i:=0;i<3;i++ {
		if t1.Link[i] != 0 {
			continue
		}

		for j:=0;j<3;j++{
			if t2.Link[j] != 0 {
				continue
			}

			if t1.Points[i] == t2.Points[j] {
				num ++
				if index1 == -1 {
					index1 = i
				}

				if index2 == -1 {
					index2 = j
				}
			}
		}
	}

	if num < 2 {
		return -1
	}

	if (index1 == 0 && index2 == 1) || (index1 == 1 && index2 == 0){
		return 0
	}else if (index1 == 1 && index2 == 2) || (index1 == 2 && index2 == 1){
		return 1
	}else if (index1 == 2 && index2 == 0) || (index1 == 0 && index2 == 2){
		return 2
	}

	return -1
}

/**
计算距离
*/
func (p *mapDataManager) Distance(pos1 *model.Pos,pos2 *model.Pos) int {
	x := pos1.GetX() - pos2.GetX()
	z := pos1.GetZ() - pos2.GetZ()
	return int(math.Sqrt(float64(x*x + z*z)))
}





























